/*
 * test_db3.cpp
 *
 *  Created on: Jan 24, 2014
 *      Author: killerg
 */

#include <queue>
#include <string>
#include <assert.h>
#include <sstream>

using namespace std;

#include "share/db_mgr.h"
#include "share/util.h"
#include "share/clock.h"

#define DATA_NUM 1
#define MIN_DATA_SIZE 1000
#define MAX_DATA_SIZE 10000

static db_mgr_t g_db;
static my_clock_t g_clock;

enum {
    START_CREATE = 0,
    CREATING  = 1,
    START_CHECK = 2,
    CHECKING = 3,
    START_DELETE = 4,
    DELETING = 5,
    FINISH = 6,
} g_state = START_DELETE;
int g_pending = 0;

static void gen_value(const string &key, Json::Value &value);
static bool check_value(const Json::Value &value);

static int s_counter = 30;

bool test_db3() {

    assert(g_db.init("192.168.1.3", "", "", "default"));
    assert(g_clock.init(5));

    while (true) {
    	g_clock.begin_update();
        switch (g_state) {
        case START_CREATE:
            {
            	for (int i=0; i<DATA_NUM; ++i) {
            		string key = fmt_str("key:%d", i);
            		Json::Value value;
            		gen_value(key, value);
            		bool res = g_db.set(key.c_str(), value, [key](db_error_t err){
            			if (DBE_Success != err) {
            				printf("stage:%d key:%s errcode:%d errmsg:%s\n",
            						g_state,
            						key.c_str(),
            						err,
            						db_strerror(err));
            			}

            			--g_pending;
            			if (g_pending == 0) {
            				g_state = START_CHECK;
            			}
            		});
            		assert(res);
            		++g_pending;
            	}
            	g_state = CREATING;
            }
            break;
        case START_CHECK:
            {
            	for (int i=0; i<DATA_NUM; ++i) {
            		string key = fmt_str("key:%d", i);
            		bool res = g_db.get(key.c_str(), [key](db_error_t err, const Json::Value &value){
            			if (DBE_Success == err) {
                			assert(check_value(value));
            			} else {
            				printf("stage:%d key:%s errcode:%d errmsg:%s\n",
            						g_state,
            						key.c_str(),
            						err,
            						db_strerror(err));
            			}
            			--g_pending;
            			if (g_pending == 0) {
            				g_state = START_DELETE;
            				--s_counter;
            			}
            		});
            		assert(res);
            		++g_pending;
            	}
            	g_state = CHECKING;
            }
            break;
        case START_DELETE:
            {
            	for (int i=0; i<DATA_NUM; ++i) {
            		string key = fmt_str("key:%d", i);
            		bool res = g_db.del(key.c_str(), [key](db_error_t err){
            			if (DBE_Success != err) {
            				printf("stage:%d key:%s errcode:%d errmsg:%s\n",
            						g_state,
            						key.c_str(),
            						err,
            						db_strerror(err));
            			}
            			--g_pending;
            			if (g_pending == 0) {
            				g_state = START_CREATE;
            			}
            		});
            		assert(res);
            		++g_pending;
            	}
            	g_state = DELETING;
            }
            break;
        }

        if (s_counter == 0)
        	break;

        g_db.update();
        g_clock.end_update();
        g_clock.wait_frame();

        if (g_clock.sec_jump) {
        	printf("state:%d pending:%d\n", g_state, g_pending);
        }
    }

    g_db.destroy();
    g_clock.destroy();

    printf("exit peacefull\n");

    return true;
}

void gen_value(const string &key, Json::Value &value) {
	stringstream ss;
	int size = random(MIN_DATA_SIZE, MAX_DATA_SIZE);
	for (int i=0; i<size; ++i)
		ss << i%10;

	value["data"] = ss.str();
	value["chksum"] = Md5(ss.str().c_str());
}

bool check_value(const Json::Value &value) {
	string md5 = value["chksum"].asCString();
	string data = value["data"].asCString();

	return md5 == Md5(data.c_str());
}
